#include "media_lib.h"

#define BUFFSIZE 256

//内部接口：解析某一个频道目录所要获取的所有内容
struct chn_context_st {
	struct mlib_st mlib_list; //频道列表
#if 0
	char **mp3_path; 
	int mp3_nr;
#endif
	glob_t mp3_path; //音频路径保存在mp3_path.gl_pathv指针数组中
					 //音频文件的个数保存在mp3_path.gl_pathc中
	int mp3_index; //当前第mp3_index+1音频文件对应的索引
	int mp3_fd; //当前第mp3_index+1音频文件对应的文件描述符
	int mp3_pos; //读到了第mp3_index+1音频文件的位置
};

//打开音频文件的下一个, 进行读取
static int __open_next (struct chn_context_st *mychn);
struct chn_context_st *__get_chn_context (const char *path);

//每一个频道都有一个chn_context_st结构, 最多有MEDIA_MAX_CHN_NR频道,频道号与对应的数组下标相等
struct chn_context_st *chns[MEDIA_MAX_CHN_NR + 1];

/*
   获取频道列表
*/
int mlib_get_chn_list (struct mlib_st **mlib, int *chn_nr)
{
	DIR *dp;
	struct dirent *entry;
	int len;
	char buf[BUFFSIZE] = {};
	int i = 0;
	struct chn_context_st *context;

	//解析媒体库得到每一个频道的路径 
	//媒体库的路径：/home/andy/media_lib
	//频道的路径：/home/andy/media_lib/music 
	dp = opendir (MEDIA_PATH);
	if (NULL == dp) {
		perror ("opendir()");
		return -1;
	}
	while (1) {
		entry = readdir (dp);
		if (NULL == entry) {
			break;
		}
		//entry->d_name 频道名
		memset (buf, '\0', BUFFSIZE);
		len = BUFFSIZE;
		strncpy (buf, MEDIA_PATH, len);
		len -= (strlen(buf) + 1);
		strncat (buf, "/", len);
		len -= 1;
		//buf 中保存的就是每一个频道的路径
		strncat (buf, entry->d_name, len);
		
		//获取频道的内容
		context = __get_chn_context (buf);
		if (NULL == context) {
			continue;
		}
		*mlib = realloc (*mlib, (i+1) * sizeof (struct mlib_st));
		if (NULL == *mlib) {
			return -1;
		}
		(*mlib)[i] = context->mlib_list;
		chns [context->mlib_list.chnid] = context;
		i++;
	}
	//值-结果参数,chn_nr保存的是频道的数量
	*chn_nr = i;
	return 0;
}


/*
   给定一个频道的路径
   媒体库：/home/andy/media_lib
   频道：/home/andy/media_lib/music(opera)(traffic)
 */
struct chn_context_st *__get_chn_context (const char *path)
{
	FILE* fp;
	char buf[BUFFSIZE] = {};
	struct chn_context_st *mychn;
	size_t len;
	static int cur_chn_id = 1;
	int ret = 0;

	strncpy (buf, path, BUFFSIZE);
	//解析频道的描述文件
	//buf中保存的是频道描述文件的路径
	strncat (buf, "/descr.txt", BUFFSIZE - strlen(path));

	//打开频道的描述文件
	fp = fopen (buf, "r");
	if (NULL == fp) {
		return NULL;
	}
	//开辟一段空间, 将描述文件的内容读出来
	mychn = malloc (sizeof (struct chn_context_st));
	if (NULL == mychn) {
		fclose (fp);
		return NULL;
	}
	len = 0;
	mychn->mlib_list.descr = NULL;
	if (-1 == getline (&mychn->mlib_list.descr, &len, fp)) {
		free (mychn);
		mychn = NULL;
		fclose (fp);
		return NULL;
	}
	//存储当前频道下的所有音频文件的路径 
	strncpy (buf, path, BUFFSIZE);
	strncat (buf, "/*.mp3", BUFFSIZE - strlen(path));
	//buf--> /home/andy/media_lib/music/*.mp3 
	memset (&mychn->mp3_path, '\0', sizeof (glob_t));
	ret = glob (buf, 0, NULL, &mychn->mp3_path);
	if (GLOB_NOMATCH == ret) {
		//该频道没有音频文件 
		printf("描述是：%s该频道没有音频文件!\n", mychn->mlib_list.descr);
		fclose(fp);
		free (mychn);
		return NULL;
	}

	//该频道是一个有效频道 
	mychn->mlib_list.chnid = cur_chn_id++;

	//当前频道对应的存储所有频道路径的数组下标
	mychn->mp3_index = 0;
	mychn->mp3_pos = 0;
	mychn->mp3_fd = open ((mychn->mp3_path).gl_pathv[mychn->mp3_index], O_RDONLY);
	return mychn;
}

ssize_t mlib_read_chn_data (int8_t chnid, void *buf, size_t size)
{
	ssize_t cnt = 0;
	//chns[chnid] 就是chnid频道对应的频道结构 
	struct chn_context_st *mychn= chns[chnid];

	//所有的音频文件的路径 mychn->mp3_path.gl_pathv 
	while (1) {
		cnt = pread (mychn->mp3_fd, buf, size, mychn->mp3_pos);
		if (-1 == cnt) {
			perror ("pread()");
			return -1;
		} else if (0 == cnt) {
			//当前文件读完了, 关闭当前文件读取下一个
			__open_next (mychn);
		} else {
			break;
		}
	}
	//改变文件的偏移位置
	mychn->mp3_pos += cnt;
	return cnt;
}

//关闭当前的文件描述符, 打开下一个并读取
static int __open_next (struct chn_context_st *mychn)
{
	//关闭当前的
	close (mychn->mp3_fd);
	mychn->mp3_index++;
	if (mychn->mp3_index == mychn->mp3_path.gl_pathc) 
	{
		mychn->mp3_index = 0;
	}
	//打开下一个
	mychn->mp3_fd = open ((mychn->mp3_path.gl_pathv)[mychn->mp3_index], O_RDONLY);
	if (-1 == mychn->mp3_fd) {
		perror ("open()");
		return -1;
	}
	mychn->mp3_pos = 0;
	return 0;
}
